package com.mooc.user.service;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.mooc.user.common.UserException;
import com.mooc.user.mapper.UserMapper;
import com.mooc.user.model.User;
import com.mooc.user.utils.BeanHelper;
import com.mooc.user.utils.HashUtils;
import com.mooc.user.utils.JwtHelper;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {


/*  @Autowired
  private FileService fileService;*/

  @Autowired
  private MailService mailService;

  @Autowired
  private UserMapper userMapper;

  @Autowired
  private StringRedisTemplate redisTemplate;

  @Value("${file.prefix}")
  private String imgPrefix;

  public List<User> getUserByQuery(User user) {
    List<User> list = userMapper.selectUsersByQuery(user);
    list.forEach(u -> {
      u.setAvatar(imgPrefix + u.getAvatar());
    });
    return list;
  }


  /**
   * 1.首先通过缓存获取
   * 2.缓存中不存在则通过数据库获取用户对象
   * 3.将用户对象写入缓存，设置缓存时间5分钟
   * 4.返回对象
   * @param id
   * @return
   */
  public User getUserById(Long id) {
   /* User queryUser = new User();
    queryUser.setId(id);
    List<User> users = getUserByQuery(queryUser);
    if (!users.isEmpty()) {
      return users.get(0);
    }
    return null;*/
   String key ="user:" + id;
    String json = redisTemplate.opsForValue().get(key);
    User user = null;
    if(Strings.isNullOrEmpty(json)){
      user = userMapper.selectById(id);
      user.setAvatar(imgPrefix + user.getAvatar());
      String string = JSON.toJSONString(user);
      redisTemplate.opsForValue().set(key,string);
      redisTemplate.expire(key,5, TimeUnit.MINUTES);
    }else{
      user = JSON.parseObject(json,User.class);

    }
   return user;
  }

  /**
   * 1.新增用户到数据
   * 2.设置redis值，
   * 3.发送邮件
   * 事务：以上3个步骤应该统一，不能出现用户数据库已经保存了，但是邮寄没有发送出去的情况
   * @param user  新增用户
   * @param enableUrl 邮件激活链接
   */
  @Transactional
  public void addAccount(User user, String enableUrl){
    //密码加密
    user.setPasswd(HashUtils.encryPassword(user.getPasswd()));
    BeanHelper.onInsert(user);
    userMapper.insert(user);
    //注册通知，即发邮件激活用户
    registerNotify(user.getEmail(), enableUrl);
  }

  private void registerNotify(String email, String enableUrl){
    String randomKey = HashUtils.hashString(email)
            + RandomStringUtils.randomAlphabetic(10);
    //把email保存到redis里面，邮件激活链接带上key
    //这样就可以去到对应的email然后去设值
    redisTemplate.opsForValue().set(randomKey,email);
    redisTemplate.expire(randomKey,1,TimeUnit.HOURS);
    String content = enableUrl + "?key=" + randomKey;
    mailService.sendMail("房产平台激活邮件",content,email);
  }

  public boolean enable(String key){

    String email = redisTemplate.opsForValue().get(key);
    //邮箱不存在，即没有填注册信息
    if(StringUtils.isBlank(email)){
      throw new UserException(UserException.Type.USER_NOT_FOUND,"无效key");
    }
    User updateUser = new User();
    updateUser.setEmail(email);
    updateUser.setEnable(1);
    userMapper.update(updateUser);
    return true;
  }

  /**
   * 校验用户名密码，生产token并返回用户对象
   * @param email
   * @param passwd
   * @return
   */
  public User auth(String email, String passwd) {
      if(StringUtils.isBlank(email) || StringUtils.isBlank(passwd)){
        throw new UserException(UserException.Type.USER_AUTH_FAIL,"User Auth Fail");
      }

      User user = new User();
      user.setEmail(email);
      user.setPasswd(HashUtils.encryPassword(passwd));
      user.setEnable(1);
    List<User> list = getUserByQuery(user);

    if(list.isEmpty()){
      throw new UserException(UserException.Type.USER_AUTH_FAIL,"User Auth Fail");
    }
    User retUser = list.get(0);

    onLogin(retUser);
    return retUser;
  }

  private void onLogin(User user) {
  String token =  JwtHelper.genToken(ImmutableMap.of("email",
            user.getEmail(),"name",user.getName(),"ts", Instant.now().getEpochSecond()+""));
  //token存到redis里面设置token过期时间
  renewToken(token, user.getEmail());
  user.setToken(token);
  }

  private String renewToken(String token, String email){
    redisTemplate.opsForValue().set(email, token);
    redisTemplate.expire(email, 30, TimeUnit.MINUTES);
    System.out.println("设置的token:" + redisTemplate.opsForValue().get(email));
    return token;
  }




  public User getLoginedUserByToken(String token)  throws  Exception{
    Map<String, String> map = null;
    try {
      map = JwtHelper.verifyToken(token);
    } catch (Exception e) {
      throw new UserException(UserException.Type.USER_NOT_LOGIN, "User not Login");
    }
     String email = map.get("email");
    System.out.println("取出redis值："+redisTemplate.opsForValue().get(email));
    Long expired = redisTemplate.getExpire(email);
    if(expired > 0){
      renewToken(token, email);
      User user = getUserByEmail(email);
      user.setToken(token);
      return user;
    }
   throw  new UserException(UserException.Type.USER_NOT_FOUND,"User not Login");
  }

  private User getUserByEmail(String email) {
    User user = new User();
    user.setEmail(email);
    List<User> list = getUserByQuery(user);
   if(!list.isEmpty()){
     return list.get(0);
   }
   throw  new UserException(UserException.Type.USER_NOT_FOUND, "user not found for" + email);
  }

  public void invalidate(String token) {
    Map<String, String> map = JwtHelper.verifyToken(token);
    redisTemplate.delete(map.get("email"));
  }
}















